
/*
 * @Author: HanYaJun
 * @Date: 2023-01-04 15:28:29
 * @Email: hanyajun@wedobest.com.cn
 * @Description: 游戏主页
 */

import ItemBlock from './ItemBlock';

/**
 * @description: 方块的基本配置
 */
export class GameConfig {
    /**行数 */
    public static row: number = 6;
    /**列数 */
    public static column: number = 6;
    /**方块的尺寸 */
    public static size: number = 100;
    /**间隔 */
    public static spacing: number = 5;
    /**边距 */
    public static padding: number = 5;

}

const trace = function (...args) {
    console.log('BoardHome【HYJ】', ...args);
}

const traceError = function (...args) {
    console.error('BoardHome【HYJ】', ...args);
}

const { ccclass, property } = cc._decorator;

@ccclass
export default class BoardHome extends cc.Component {
    // #region (地图数据)
    /**方块坐标 */
    private positionMap: cc.Vec2[][] = [];
    /**地图宽度 */
    private width: number = null;
    /**地图高度 */
    private height: number = null;
    /**起始 x 坐标 */
    private beginX: number = null;
    /**起始 y 坐标 */
    private beginY: number = null;
    // #endregion

    /**方块放置节点 */
    private gameLogicLayer: cc.Node = null;
    /**创建对象池 */
    private enemyPool: cc.NodePool = null;
    /**方块预制 */
    private itemPrefab: cc.Prefab = null;
    /**方块预制地址 */
    private blockStr: string = null;
    /**背景模板 */
    private blockBg: cc.Node = null;
    /**关卡 */
    private level: number = 1;
    /**关卡节点 */
    private passLabel: cc.Node = null;
    /**秒数 */
    private miaoShu: number = null;
    /**过关成功 */
    private passSuccess: cc.Node = null;
    /**过关失败 */
    private passFailured: cc.Node = null;
    /**检测结果 */
    private testingResult: cc.Node = null;
    /**是否开始计时 */
    private beginTiem: boolean = null;
    /**检测报告 */
    private examiningReport: cc.Node = null;
    /**查找失败 */
    private searchFailure: cc.Node = null;

    /**
     * @description: 当附加到一个激活的节点上或者其节点第一次激活时候调用
     */
    protected onLoad(): void {
        // 背景设置
        this.blockBg = cc.find('backGround/fittingTop/blockBg', this.node);
        this.passLabel = cc.find('backGround/fittingTop/customsPass/passBg/passLabel', this.node);
        this.passSuccess = cc.find('backGround/fittingTop/passSuccess', this.node);
        this.passFailured = cc.find('backGround/fittingTop/passFailured', this.node);
        this.testingResult = cc.find('backGround/fittingTop/testingResult', this.node);
        this.examiningReport = cc.find('backGround/fittingTop/examiningReport', this.node);
        this.searchFailure = cc.find('backGround/fittingTop/searchFailure', this.node);
        // 事件监听
        this.node.on('correct', this.findSuccess, this);
        this.node.on('error', this.findDefeated, this);
        this.node.on('beginTimeCount', this.beginTimeCount, this);
        this.node.on('findReport', this.testReport, this);
        this.initData();
    }

    /**
     * @description: 初始化数据
     */
    private initData(): void {
        // 获取缓存数据(关卡)
        let progressLevel = cc.sys.localStorage.getItem('progressLevel');
        if (progressLevel) {
            this.level = parseInt(progressLevel);
        } else {
            cc.sys.localStorage.setItem('progressLevel', this.level);
        }
        // 设置关卡
        if (this.passLabel) {
            let level: cc.Label = this.passLabel.getComponent(cc.Label);
            level.string = '第' + this.level + '关';
        }
        this.passSuccess.active = false;
        this.passFailured.active = false;
        this.searchFailure.active = false;
        this.createMatrix();
        this.loadPrefab(() => {
            if (this.level <= 2) {
                this.twoTimeTwo();
                this.createBlock(2, 2);
            } else if (2 < this.level && this.level <= 5) {
                this.threeTimesThree();
                this.createBlock(3, 3);
            } else if (5 < this.level && this.level <= 9) {
                this.fourTimesFour();
                this.createBlock(4, 4);
            } else if (9 < this.level && this.level <= 14) {
                this.fiveTimesFive();
                this.createBlock(5, 5);
            } else if (14 < this.level && this.level <= 20) {
                this.sixTimesSix();
                this.createBlock(6, 6);
            }
        });
        this.countDown(60);
    }

    /**
     * @description: 倒计时开始
     */
    private beginTimeCount(): void {
        this.unscheduleAllCallbacks();
        this.countDown(60);
    }

    /**
     * @description: 倒计时
     * @param {number} setSecondTime 秒数
     * @return {*}
     */
    private countDown(setSecondTime: number): void {
        let fenZhong: number = Math.floor(setSecondTime / 60);
        this.miaoShu = Math.floor(setSecondTime % 60);
        let beignTime = cc.sys.localStorage.getItem('beignTime');
        if (beignTime) {
            this.beginTiem = beignTime;
        } else {
            this.beginTiem = true;
        }
        if (this.beginTiem) {
            this.schedule(() => {
                if (this.miaoShu === 0) {
                    fenZhong = fenZhong - 1;
                    this.miaoShu = 60;
                }
                this.miaoShu = this.miaoShu - 1;
                // 倒计时结束，过关失败
                if (this.miaoShu <= 0) {
                    this.passFailure();
                }
                trace('倒计时:', String(fenZhong) + ":", +String(this.miaoShu));
                let countDown: cc.Label = cc.find('backGround/fittingTop/score/scoreBg/countDown', this.node).getComponent(cc.Label);
                if (countDown) {
                    countDown.string = String(this.miaoShu);
                }
            }, 1, setSecondTime - 1);
        }
    }

    /**
    * @description: 加载方块预制
    * @param {function} finish
    */
    private loadPrefab(finish: () => void): void {
        // 方块预制地址
        this.blockStr = 'home/colorBlock';
        // 方块预制获取
        cc.loader.loadRes(this.blockStr, cc.Prefab, (err, res) => {
            if (!err) {
                this.itemPrefab = res;
                // 创建对象池
                this.enemyPool = new cc.NodePool();
                let initCount: number = 100;
                for (let i = 0; i < initCount; i++) {
                    // 创建节点
                    let enemy: cc.Node = cc.instantiate(this.itemPrefab);
                    // 通过 put 接口放入对象池
                    this.enemyPool.put(enemy);
                }
                finish();
            } else {
                traceError('err:', err);
            }
        });
    }

    /**
     * @description: 创建一个 8 X 8 矩阵 生成位置表
     */
    private createMatrix(): void {
        // 计算宽高
        this.width = (GameConfig.padding * 2) + (GameConfig.size * GameConfig.column) + (GameConfig.spacing * (GameConfig.column - 1));
        trace('背景地图的宽, this.width:', this.width);
        this.blockBg.width = this.width;
        this.height = (GameConfig.padding * 2) + (GameConfig.size * GameConfig.row) + (GameConfig.spacing * (GameConfig.row - 1));
        trace('背景地图的高, this.height:', this.height);
        this.blockBg.height = this.height;
    }

    /**
     * @description: 创建关卡
     * @param {number} beginX 开始 X 坐标
     * @param {number} beginY 开始 Y 坐标
     * @param {number} column 列
     * @param {number} row    行
     * @return {*}
     */
    private createLevel(beginX: number, beginY: number, column: number, row: number): void {
        // 从左到右计算每一列方块的位置
        for (let c = 0; c < column; c++) {
            let countSet = [];
            let x: number = beginX + c * (GameConfig.size + GameConfig.spacing);
            // 从下到上计算该列的每一行方块的位置
            for (let r = 0; r < row; r++) {
                let y: number = beginY + r * (GameConfig.size + GameConfig.spacing);
                countSet.push(cc.v2(x, y));
            }
            this.positionMap.push(countSet);
        }
    }

    /**
     * @description: 2*2规格2张
     */
    private twoTimeTwo(): void {
        this.positionMap = [];
        // 以左下角为原点，计算第一个方块的位置
        let twoX: number = -(GameConfig.padding / 2) - (GameConfig.size / 2);
        let twoY: number = -(GameConfig.padding / 2) - (GameConfig.size / 2);
        this.createLevel(twoX, twoY, 2, 2);
    }

    /**
     * @description: 3*3规格3张
     */
    private threeTimesThree(): void {
        this.positionMap = [];
        // 以左下角为原点，计算第一个方块的位置
        let threeX: number = - GameConfig.size - GameConfig.padding;
        let threeY: number = - GameConfig.size - GameConfig.padding;
        this.createLevel(threeX, threeY, 3, 3);
    }

    /**
     * @description: 4*4规格4张
     */
    private fourTimesFour(): void {
        this.positionMap = [];
        // 以左下角为原点，计算第一个方块的位置
        let fourX: number = -(GameConfig.padding / 2) - (3 * (GameConfig.size / 2)) - GameConfig.padding;
        let fourY: number = -(GameConfig.padding / 2) - (3 * (GameConfig.size / 2)) - GameConfig.padding;
        this.createLevel(fourX, fourY, 4, 4);
    }

    /**
     * @description: 5*5规格5张
     */
    private fiveTimesFive(): void {
        this.positionMap = [];
        // 以左下角为原点，计算第一个方块的位置
        let fourX: number = -(2 * GameConfig.padding) - (2 * GameConfig.size);
        let fourY: number = -(2 * GameConfig.padding) - (2 * GameConfig.size);
        this.createLevel(fourX, fourY, 5, 5);
    }

    /**
     * @description: 6*6规格6张
     */
    private sixTimesSix(): void {
        this.positionMap = [];
        // 以左下角为原点,计算第一个方块的位置
        let sixX: number = -(this.width / 2) + GameConfig.padding + (GameConfig.size / 2);
        let sixY: number = -(this.height / 2) + GameConfig.padding + (GameConfig.size / 2);
        this.createLevel(sixX, sixY, 6, 6);
    }

    /**
     * @description: 获取坐标
     * @param {number} x 列
     * @param {number} y 行
     * @return {*}
     */
    public getPosition(x: number, y: number): cc.Vec2 {
        return this.positionMap[x][y];
    }

    /**
     * @description: 创建方块
     * @param {number} column 列
     * @param {number} row    行
     * @return {*}
     */
    private createBlock(column: number, row: number): void {
        // 清空背景子节点
        this.blockBg.removeAllChildren();
        // 颜色值(随机数 含最大值，含最小值)
        let colorIndex: number = Math.floor(Math.random() * 9);
        // 不同颜色值
        let diffColorIndex: number = Math.floor(Math.random() * (column * row)) + 1;
        // 设置执行次数
        cc.sys.localStorage.setItem('executeCount', 1);
        for (let c = 0; c < column; c++) {
            for (let r = 0; r < row; r++) {
                let enemy: cc.Node = null;
                if (this.enemyPool.size() > 0) {
                    // 通过 size 接口判断对象池中是否有空闲的对象
                    enemy = this.enemyPool.get();
                } else {
                    // 如果没有空闲对象，也就是对象池中备用对象不够时，我们就用 cc.instantiate 重新创建
                    enemy = cc.instantiate(this.itemPrefab);
                }
                enemy.parent = this.blockBg;
                enemy.getComponent(ItemBlock).initData({ position: this.getPosition(c, r), index: colorIndex, diffIndex: diffColorIndex });
            }
        }
    }

    /**
     * @description: 查找成功
     */
    private findSuccess(): void {
        cc.sys.localStorage.setItem('progressLevel', this.level + 1);
        this.unscheduleAllCallbacks();
        if (this.passSuccess) {
            this.passSuccess.active = true;
            cc.tween(this.passSuccess)
                .delay(2)
                .call(() => {
                    this.initData();
                    this.testResult();
                })
                .start();
        }
    }

    /**
     * @description: 查找失败
     */
    private findDefeated(): void {
        if (this.miaoShu >= 5) {
            this.searchFailure.active = true;
            cc.tween(this.searchFailure)
                .delay(1)
                .call(() => {
                    this.searchFailure.active = false;
                })
                .start();
            this.miaoShu -= 5;
        } else {
            this.passFailure();
        }
    }

    /**
     * @description: 过关失败
     */
    private passFailure(): void {
        this.unscheduleAllCallbacks();
        if (this.passFailured) {
            this.passFailured.active = true;
            cc.tween(this.passFailured)
                .delay(2)
                .call(() => {
                    this.initData();
                    this.testResult();
                })
                .start();
        }
    }

    /**
     * @description: 检测结果
     */
    private testResult(): void {
        // 方块预制地址
        let resultStr: string = 'home/testRes';
        // 方块预制获取
        cc.loader.loadRes(resultStr, cc.Prefab, (err, res) => {
            if (!err) {
                // 创建节点
                let enemy: cc.Node = cc.instantiate(res);
                if (enemy && this.testingResult) {
                    enemy.parent = this.testingResult;
                    this.unscheduleAllCallbacks();
                    let countDown: cc.Label = cc.find('backGround/fittingTop/score/scoreBg/countDown', this.node).getComponent(cc.Label);
                    if (countDown) {
                        countDown.string = 60 + '';
                    }
                    cc.sys.localStorage.setItem('beignTime', false);
                }
            } else {
                traceError('err:', err);
            }
        });
    }

    /**
     * @description: 检测报告
     */
    private testReport(): void {
        // 检测报告地址
        let resultStr: string = 'home/testReport';
        // 方块预制获取
        cc.loader.loadRes(resultStr, cc.Prefab, (err, res) => {
            if (!err) {
                // 创建节点
                let enemy: cc.Node = cc.instantiate(res);
                if (enemy && this.examiningReport) {
                    enemy.parent = this.examiningReport;
                }
            } else {
                traceError('err:', err);
            }
        });
    }

    /**
     * @description: 当该组件被销毁时调用
     */
    protected onDestroy(): void {
        this.enemyPool.clear();
        this.positionMap = [];
        this.unscheduleAllCallbacks();
        // 关闭监听
        this.node.off('correct', this.findSuccess, this);
        this.node.off('error', this.findDefeated, this);
        this.node.off('beginTimeCount', this.beginTimeCount, this);
        this.node.off('findReport', this.testReport, this);
    }
}
